package com.jingdianjichi.auth.application.controller;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import com.alibaba.fastjson.JSON;
import com.google.common.base.Preconditions;
import com.jingdianjichi.auth.application.convert.AuthUserDTOConverter;
import com.jingdianjichi.auth.application.dto.AuthUserDTO;
import com.jingdianjichi.auth.common.entity.Result;
import com.jingdianjichi.auth.common.util.RedisUtil;
import com.jingdianjichi.auth.domain.entity.AuthUserBO;
import com.jingdianjichi.auth.domain.service.AuthUserDomainService;
import com.jingdianjichi.auth.util.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;



/**
 * 用户管理控制器
 * 负责处理用户相关的HTTP请求，包括用户注册、更新、删除、状态变更等操作
 * 以及基于Sa-Token的用户登录认证功能
 * 
 * @author ChickenWing
 * @date 2023/10/28
 */
@RestController
@RequestMapping("/user/")
@Slf4j
public class UserController {

    /**
     * 用户领域服务
     * 注入用户业务逻辑处理服务，负责具体的用户操作业务逻辑
     */
    @Resource
    private AuthUserDomainService authUserDomainService;

    @Resource
    private RedisUtil redisUtil;

    private static final String LOGIN_PREFIX = "loginCode";

    private static final SecureRandom RANDOM = new SecureRandom();

    /**
     * 获取验证码接口
     * 前端点击获取验证码按钮，后端生成验证码并返回
     * @return
     */
    @RequestMapping("getCaptcha")
    public Result<String> getCaptcha(@RequestParam("phone") String phone){
        // 测试用，从请求参数中获取手机号
        String fromUserName = phone;
        // 生成3位随机数字验证码
        int captcha = 100 + RANDOM.nextInt(900); // 100-999之间的随机数
        String key = redisUtil.buildKey(LOGIN_PREFIX, String.valueOf(captcha));
        redisUtil.setNx(key, fromUserName, 5L, TimeUnit.MINUTES);
        // 发送验证码到用户
        log.info("发送验证码到用户{}：{}", fromUserName, captcha);
        return Result.ok(String.valueOf(captcha));

    }

    /**
     * 用户注册接口
     * 接收前端传递的用户注册信息，进行参数校验后调用领域服务完成用户注册
     * 
     * @param authUserDTO 用户注册信息DTO，包含用户名、邮箱、密码等基本信息
     * @return Result<Boolean> 注册结果，true表示注册成功，false表示注册失败
     */
    @RequestMapping("register")
    public Result<Boolean> register(@RequestBody AuthUserDTO authUserDTO) {
        try {
            // 记录请求参数日志，便于调试和问题排查
            if (log.isInfoEnabled()) {
                log.info("UserController.register.dto:{}", JSON.toJSONString(authUserDTO));
            }
            // 校验用户输入的基本信息（用户名、邮箱、密码不能为空）
            checkUserInfo(authUserDTO);
            // 将DTO转换为业务对象BO，用于领域层处理
            AuthUserBO authUserBO = new AuthUserBO();
            BeanUtils.copyProperties(authUserDTO, authUserBO);
            // 调用领域服务执行用户注册业务逻辑
            return Result.ok(authUserDomainService.register(authUserBO));
        } catch (Exception e) {
            // 记录异常日志并返回友好的错误信息给前端
            log.error("UserController.register.error:{}", e.getMessage(), e);
            return Result.fail("注册用户失败");
        }
    }

    /**
     * 修改用户信息接口
     * 接收前端传递的用户更新信息，进行参数校验后调用领域服务完成用户信息更新
     * 注意：更新操作会同步更新缓存中的用户信息
     * 
     * @param authUserDTO 用户更新信息DTO，包含需要更新的用户字段
     * @return Result<Boolean> 更新结果，true表示更新成功，false表示更新失败
     */
//    @RequestMapping("update")
//    public Result<Boolean> update(@RequestBody AuthUserDTO authUserDTO) {
//        try {
//            // 记录请求参数日志
//            if (log.isInfoEnabled()) {
//                log.info("UserController.update.dto:{}", JSON.toJSONString(authUserDTO));
//            }
//            // 校验用户输入的基本信息
//            checkUserInfo(authUserDTO);
//            // DTO转BO，准备传递给领域层
//            AuthUserBO authUserBO = AuthUserDTOConverter.INSTANCE.convertDTOToBO(authUserDTO);
//            // 调用领域服务执行用户信息更新业务逻辑
//            return Result.ok(authUserDomainService.update(authUserBO));
//        } catch (Exception e) {
//            // 异常处理和日志记录
//            log.error("UserController.update.error:{}", e.getMessage(), e);
//            return Result.fail("更新用户信息失败");
//        }
//    }

    /**
     * 删除用户接口
     * 接收前端传递的用户ID，执行用户删除操作（逻辑删除）
     * 注意：这里实际调用的是update方法，应该调用delete方法
     * 
     * @param authUserDTO 包含用户ID的DTO对象
     * @return Result<Boolean> 删除结果，true表示删除成功，false表示删除失败
     */
//    @RequestMapping("delete")
//    public Result<Boolean> delete(@RequestBody AuthUserDTO authUserDTO) {
//        try {
//            // 记录删除操作的请求参数
//            if (log.isInfoEnabled()) {
//                log.info("UserController.delete.dto:{}", JSON.toJSONString(authUserDTO));
//            }
//            // DTO转BO
//            AuthUserBO authUserBO = AuthUserDTOConverter.INSTANCE.convertDTOToBO(authUserDTO);
//            // TODO: 这里应该调用delete方法而不是update方法
//            return Result.ok(authUserDomainService.update(authUserBO));
//        } catch (Exception e) {
//            // 异常日志记录（注意：这里的日志标识应该是delete而不是update）
//            log.error("UserController.delete.error:{}", e.getMessage(), e);
//            return Result.fail("删除用户信息失败");
//        }
//    }

    /**
     * 校验用户基本信息
     * 使用Google Guava的Preconditions进行参数校验，如果校验失败会抛出IllegalArgumentException
     * 
     * @param authUserDTO 需要校验的用户信息DTO
     * @throws IllegalArgumentException 当必填字段为空时抛出异常
     */
    private void checkUserInfo(@RequestBody AuthUserDTO authUserDTO) {
        // 校验用户名不能为空
        Preconditions.checkArgument(!StringUtils.isBlank(authUserDTO.getUserName()), "用户名不能为空");
        // 校验邮箱地址不能为空
        Preconditions.checkArgument(!StringUtils.isBlank(authUserDTO.getEmail()), "邮件地址不能为空");
        // 校验密码不能为空
        Preconditions.checkArgument(!StringUtils.isBlank(authUserDTO.getPassword()), "密码不能为空");
    }

    /**
     * 用户状态变更接口（启用/禁用）
     * 管理员可以通过此接口启用或禁用用户账户
     *
     * @param authUserDTO 包含用户ID和状态信息的DTO对象
     * @return Result<Boolean> 状态变更结果，true表示操作成功，false表示操作失败
     */
//    @RequestMapping("changeStatus")
//    public Result<Boolean> changeStatus(@RequestBody AuthUserDTO authUserDTO) {
//        try {
//            // 记录状态变更操作的请求参数
//            if (log.isInfoEnabled()) {
//                log.info("UserController.changeStatus.dto:{}", JSON.toJSONString(authUserDTO));
//            }
//            // 校验用户状态字段不能为空
//            Preconditions.checkNotNull(authUserDTO.getStatus(), "用户状态不能为空");
//            // DTO转BO
//            AuthUserBO authUserBO = AuthUserDTOConverter.INSTANCE.convertDTOToBO(authUserDTO);
//            // 调用领域服务更新用户状态
//            return Result.ok(authUserDomainService.update(authUserBO));
//        } catch (Exception e) {
//            // 异常处理和日志记录
//            log.error("UserController.changeStatus.error:{}", e.getMessage(), e);
//            return Result.fail("启用/禁用用户信息失败");
//        }
//    }

    /**
     * 基于验证码的登录接口
     * @param captcha 验证码
     * @return
     */
    @RequestMapping("doLogin")
    public Result doLogin(String captcha) {
        try {
            Preconditions.checkNotNull(captcha,"验证码不能为空");
            log.info("接收用户验证码，开始校验:{}", captcha);
            return Result.ok(authUserDomainService.login(captcha));
        } catch (Exception e) {
            log.error("UserController.doLogin.error:{}", e.getMessage(), e);
            return Result.fail("登录失败");
        }
    }

    /**
     * 获取用户信息
     */
    @RequestMapping("getUserInfo")
    public Result<AuthUserDTO> getUserInfo(@RequestBody AuthUserDTO authUserDTO) {
        try {
            log.info("测试服务间调用是否正确携带用户信息,当前登录用户ID:{}", LoginUtil.getLoginId());
            if (log.isInfoEnabled()) {
                log.info("UserController.getUserInfo.dto:{}", JSON.toJSONString(authUserDTO));
            }
            Preconditions.checkArgument(!StringUtils.isBlank(authUserDTO.getUserName()), "用户名不能为空");
            AuthUserBO authUserBO = AuthUserDTOConverter.INSTANCE.convertDTOToBO(authUserDTO);
            AuthUserBO userInfo = authUserDomainService.getUserInfo(authUserBO);
            BeanUtils.copyProperties(userInfo,authUserDTO);
            return Result.ok(authUserDTO);
        } catch (Exception e) {
            log.error("UserController.getUserInfo.error:{}", e.getMessage(), e);
            return Result.fail("获取用户信息失败");
        }
    }

    /**
     * 用户退出
     */
    @RequestMapping("logOut")
    public Result logOut(@RequestParam String userName) {
        try {
            log.info("UserController.logOut.userName:{}", userName);
            Preconditions.checkArgument(!StringUtils.isBlank(userName), "用户名不能为空");
            StpUtil.logout(userName);
            return Result.ok();
        } catch (Exception e) {
            log.error("UserController.logOut.error:{}", e.getMessage(), e);
            return Result.fail("用户登出失败");
        }
    }

    /**
     * 查询用户登录状态接口
     * 用于检查当前会话是否已登录
     * 测试访问地址：http://localhost:8081/user/isLogin
     * 
     * @return String 返回当前会话的登录状态描述
     */
    @RequestMapping("isLogin")
    public String isLogin() {
        // 调用Sa-Token的isLogin方法检查当前会话是否已登录
        return "当前会话是否登录：" + StpUtil.isLogin();
    }

    /**
     * 修改用户信息
     */
    @RequestMapping("update")
    public Result<Boolean> update(@RequestBody AuthUserDTO authUserDTO) {
        try {
            if (log.isInfoEnabled()) {
                log.info("UserController.update.dto:{}", JSON.toJSONString(authUserDTO));
            }
            checkUserInfo(authUserDTO);
            AuthUserBO authUserBO = AuthUserDTOConverter.INSTANCE.convertDTOToBO(authUserDTO);
            return Result.ok(authUserDomainService.update(authUserBO));
        } catch (Exception e) {
            log.error("UserController.update.error:{}", e.getMessage(), e);
            return Result.fail("更新用户信息失败");
        }
    }

}
